package com.example.inventoryservice.actor;

import akka.actor.AbstractPersistentActor;
import akka.actor.Props;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import akka.persistence.SnapshotOffer;
import com.example.inventoryservice.event.*;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 持久化库存Actor
 * 实现事件溯源模式，所有库存变更都通过事件记录
 */
@Component("persistentInventoryActor")
public class PersistentInventoryActor extends AbstractPersistentActor {

    private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
    
    private InventoryState state = new InventoryState();
    
    public static Props props() {
        return Props.create(PersistentInventoryActor.class);
    }
    
    @Override
    public String persistenceId() {
        return "inventory-" + getSelf().path().name();
    }
    
    @Override
    public void preStart() {
        // 初始化库存数据
        if (state.getAvailableInventory().isEmpty()) {
            state.getAvailableInventory().put("PRODUCT_001", 100);
            state.getAvailableInventory().put("PRODUCT_002", 50);
            state.getAvailableInventory().put("PRODUCT_003", 200);
            log.info("库存Actor启动，初始库存: {}", state.getAvailableInventory());
        }
    }
    
    @Override
    public Receive createReceive() {
        return receiveBuilder()
                .match(ReserveInventory.class, this::handleReserveInventory)
                .match(ConfirmInventory.class, this::handleConfirmInventory)
                .match(ReleaseInventory.class, this::handleReleaseInventory)
                .match(GetInventoryStatus.class, this::handleGetInventoryStatus)
                .match(InitializeInventory.class, this::handleInitializeInventory)
                .matchAny(o -> log.warning("收到未知消息: {}", o))
                .build();
    }
    
    @Override
    public Receive createReceiveRecover() {
        return receiveBuilder()
                .match(InventoryReservedEvent.class, this::handleInventoryReservedEvent)
                .match(InventoryConfirmedEvent.class, this::handleInventoryConfirmedEvent)
                .match(InventoryReleasedEvent.class, this::handleInventoryReleasedEvent)
                .match(InventoryInitializedEvent.class, this::handleInventoryInitializedEvent)
                .match(SnapshotOffer.class, ss -> {
                    log.info("恢复快照: {}", ss);
                    state = (InventoryState) ss.snapshot();
                })
                .build();
    }
    
    /**
     * 处理预留库存命令
     */
    private void handleReserveInventory(ReserveInventory reserveInventory) {
        log.info("处理预留库存请求: 订单ID={}, 商品列表={}", 
            reserveInventory.getOrderId(), reserveInventory.getItems());
        
        try {
            Map<String, Integer> orderReservation = new HashMap<>();
            boolean canReserve = true;
            
            // 检查库存是否足够
            for (OrderItem item : reserveInventory.getItems()) {
                String productId = item.getProductId();
                Integer requestedQty = item.getQuantity();
                Integer availableQty = state.getAvailableInventory().getOrDefault(productId, 0);
                
                if (availableQty < requestedQty) {
                    canReserve = false;
                    log.warning("库存不足: 商品ID={}, 请求数量={}, 可用数量={}", 
                        productId, requestedQty, availableQty);
                    break;
                }
                
                orderReservation.put(productId, requestedQty);
            }
            
            if (canReserve) {
                // 创建库存预留事件
                InventoryReservedEvent event = new InventoryReservedEvent(
                    reserveInventory.getOrderId(),
                    orderReservation,
                    LocalDateTime.now()
                );
                
                // 持久化事件
                persist(event, evt -> {
                    handleInventoryReservedEvent(evt);
                    
                    // 保存快照（每10个事件保存一次）
                    if (lastSequenceNr() % 10 == 0) {
                        saveSnapshot(state);
                    }
                    
                    log.info("库存预留成功，事件已持久化: 订单ID={}, 预留详情={}", 
                        reserveInventory.getOrderId(), orderReservation);
                    
                    getSender().tell(new InventoryReserved(reserveInventory.getOrderId(), "SUCCESS", orderReservation), getSelf());
                });
            } else {
                log.warning("库存预留失败: 订单ID={}, 库存不足", reserveInventory.getOrderId());
                getSender().tell(new InventoryReserved(reserveInventory.getOrderId(), "INSUFFICIENT_INVENTORY", null), getSelf());
            }
            
        } catch (Exception e) {
            log.error("预留库存异常: {}", e.getMessage(), e);
            getSender().tell(new InventoryReserved(reserveInventory.getOrderId(), "ERROR", null), getSelf());
        }
    }
    
    /**
     * 处理确认库存命令（订单支付后）
     */
    private void handleConfirmInventory(ConfirmInventory confirmInventory) {
        log.info("处理确认库存请求: 订单ID={}", confirmInventory.getOrderId());
        
        try {
            Map<String, Integer> reservation = state.getReservedInventory().get(confirmInventory.getOrderId());
            if (reservation != null) {
                // 创建库存确认事件
                InventoryConfirmedEvent event = new InventoryConfirmedEvent(
                    confirmInventory.getOrderId(),
                    reservation,
                    LocalDateTime.now()
                );
                
                // 持久化事件
                persist(event, evt -> {
                    handleInventoryConfirmedEvent(evt);
                    
                    if (lastSequenceNr() % 10 == 0) {
                        saveSnapshot(state);
                    }
                    
                    log.info("库存确认成功，事件已持久化: 订单ID={}, 确认详情={}", 
                        confirmInventory.getOrderId(), reservation);
                    
                    getSender().tell(new InventoryConfirmed(confirmInventory.getOrderId(), "SUCCESS"), getSelf());
                });
            } else {
                log.warning("未找到预留库存: 订单ID={}", confirmInventory.getOrderId());
                getSender().tell(new InventoryConfirmed(confirmInventory.getOrderId(), "NOT_FOUND"), getSelf());
            }
            
        } catch (Exception e) {
            log.error("确认库存异常: {}", e.getMessage(), e);
            getSender().tell(new InventoryConfirmed(confirmInventory.getOrderId(), "ERROR"), getSelf());
        }
    }
    
    /**
     * 处理释放库存命令（订单取消后）
     */
    private void handleReleaseInventory(ReleaseInventory releaseInventory) {
        log.info("处理释放库存请求: 订单ID={}", releaseInventory.getOrderId());
        
        try {
            Map<String, Integer> reservation = state.getReservedInventory().get(releaseInventory.getOrderId());
            if (reservation != null) {
                // 创建库存释放事件
                InventoryReleasedEvent event = new InventoryReleasedEvent(
                    releaseInventory.getOrderId(),
                    reservation,
                    LocalDateTime.now()
                );
                
                // 持久化事件
                persist(event, evt -> {
                    handleInventoryReleasedEvent(evt);
                    
                    if (lastSequenceNr() % 10 == 0) {
                        saveSnapshot(state);
                    }
                    
                    log.info("库存释放成功，事件已持久化: 订单ID={}, 释放详情={}", 
                        releaseInventory.getOrderId(), reservation);
                    
                    getSender().tell(new InventoryReleased(releaseInventory.getOrderId(), "SUCCESS"), getSelf());
                });
            } else {
                log.warning("未找到预留库存: 订单ID={}", releaseInventory.getOrderId());
                getSender().tell(new InventoryReleased(releaseInventory.getOrderId(), "NOT_FOUND"), getSelf());
            }
            
        } catch (Exception e) {
            log.error("释放库存异常: {}", e.getMessage(), e);
            getSender().tell(new InventoryReleased(releaseInventory.getOrderId(), "ERROR"), getSelf());
        }
    }
    
    /**
     * 处理获取库存状态命令
     */
    private void handleGetInventoryStatus(GetInventoryStatus getStatus) {
        log.info("处理获取库存状态请求");
        
        try {
            Map<String, Object> status = new HashMap<>();
            status.put("availableInventory", new HashMap<>(state.getAvailableInventory()));
            status.put("reservedInventory", new HashMap<>(state.getReservedInventory()));
            status.put("lastUpdated", state.getLastUpdated());
            
            getSender().tell(new InventoryStatus(status), getSelf());
            
        } catch (Exception e) {
            log.error("获取库存状态异常: {}", e.getMessage(), e);
            getSender().tell(new InventoryStatus(null), getSelf());
        }
    }
    
    /**
     * 处理初始化库存命令
     */
    private void handleInitializeInventory(InitializeInventory initializeInventory) {
        log.info("处理初始化库存请求: {}", initializeInventory.getInitialInventory());
        
        try {
            // 创建库存初始化事件
            InventoryInitializedEvent event = new InventoryInitializedEvent(
                initializeInventory.getInitialInventory(),
                LocalDateTime.now()
            );
            
            // 持久化事件
            persist(event, evt -> {
                handleInventoryInitializedEvent(evt);
                
                if (lastSequenceNr() % 10 == 0) {
                    saveSnapshot(state);
                }
                
                log.info("库存初始化成功，事件已持久化: {}", initializeInventory.getInitialInventory());
                
                getSender().tell(new InventoryInitialized("SUCCESS"), getSelf());
            });
            
        } catch (Exception e) {
            log.error("初始化库存异常: {}", e.getMessage(), e);
            getSender().tell(new InventoryInitialized("ERROR"), getSelf());
        }
    }
    
    /**
     * 处理库存预留事件（状态更新）
     */
    private void handleInventoryReservedEvent(InventoryReservedEvent event) {
        // 更新预留库存
        state.getReservedInventory().put(event.getOrderId(), event.getReservedItems());
        
        // 减少可用库存
        for (Map.Entry<String, Integer> entry : event.getReservedItems().entrySet()) {
            String productId = entry.getKey();
            Integer reservedQty = entry.getValue();
            Integer currentQty = state.getAvailableInventory().getOrDefault(productId, 0);
            state.getAvailableInventory().put(productId, currentQty - reservedQty);
        }
        
        state.setLastUpdated(event.getTimestamp());
        
        log.info("库存状态已更新 - 预留: 订单ID={}, 预留详情={}", 
            event.getOrderId(), event.getReservedItems());
    }
    
    /**
     * 处理库存确认事件（状态更新）
     */
    private void handleInventoryConfirmedEvent(InventoryConfirmedEvent event) {
        // 确认预留的库存，从预留列表中移除
        state.getReservedInventory().remove(event.getOrderId());
        state.setLastUpdated(event.getTimestamp());
        
        log.info("库存状态已更新 - 确认: 订单ID={}, 确认详情={}", 
            event.getOrderId(), event.getConfirmedItems());
    }
    
    /**
     * 处理库存释放事件（状态更新）
     */
    private void handleInventoryReleasedEvent(InventoryReleasedEvent event) {
        // 释放预留的库存
        state.getReservedInventory().remove(event.getOrderId());
        
        // 恢复可用库存
        for (Map.Entry<String, Integer> entry : event.getReleasedItems().entrySet()) {
            String productId = entry.getKey();
            Integer releasedQty = entry.getValue();
            Integer currentQty = state.getAvailableInventory().getOrDefault(productId, 0);
            state.getAvailableInventory().put(productId, currentQty + releasedQty);
        }
        
        state.setLastUpdated(event.getTimestamp());
        
        log.info("库存状态已更新 - 释放: 订单ID={}, 释放详情={}", 
            event.getOrderId(), event.getReleasedItems());
    }
    
    /**
     * 处理库存初始化事件（状态更新）
     */
    private void handleInventoryInitializedEvent(InventoryInitializedEvent event) {
        state.getAvailableInventory().clear();
        state.getAvailableInventory().putAll(event.getInitialInventory());
        state.getReservedInventory().clear();
        state.setLastUpdated(event.getTimestamp());
        
        log.info("库存状态已更新 - 初始化: {}", event.getInitialInventory());
    }
    
    // 命令消息类
    public static class ReserveInventory {
        private String orderId;
        private List<OrderItem> items;

        public ReserveInventory(String orderId, List<OrderItem> items) {
            this.orderId = orderId;
            this.items = items;
        }

        public String getOrderId() { return orderId; }
        public List<OrderItem> getItems() { return items; }
    }

    public static class ConfirmInventory {
        private String orderId;

        public ConfirmInventory(String orderId) {
            this.orderId = orderId;
        }

        public String getOrderId() { return orderId; }
    }

    public static class ReleaseInventory {
        private String orderId;

        public ReleaseInventory(String orderId) {
            this.orderId = orderId;
        }

        public String getOrderId() { return orderId; }
    }

    public static class GetInventoryStatus {
        public GetInventoryStatus() {}
    }
    
    public static class InitializeInventory {
        private Map<String, Integer> initialInventory;
        
        public InitializeInventory(Map<String, Integer> initialInventory) {
            this.initialInventory = initialInventory;
        }
        
        public Map<String, Integer> getInitialInventory() { return initialInventory; }
    }

    // 响应消息类
    public static class InventoryReserved {
        private String orderId;
        private String status;
        private Map<String, Integer> reservedItems;

        public InventoryReserved(String orderId, String status, Map<String, Integer> reservedItems) {
            this.orderId = orderId;
            this.status = status;
            this.reservedItems = reservedItems;
        }

        public String getOrderId() { return orderId; }
        public String getStatus() { return status; }
        public Map<String, Integer> getReservedItems() { return reservedItems; }
    }

    public static class InventoryConfirmed {
        private String orderId;
        private String status;

        public InventoryConfirmed(String orderId, String status) {
            this.orderId = orderId;
            this.status = status;
        }

        public String getOrderId() { return orderId; }
        public String getStatus() { return status; }
    }

    public static class InventoryReleased {
        private String orderId;
        private String status;

        public InventoryReleased(String orderId, String status) {
            this.orderId = orderId;
            this.status = status;
        }

        public String getOrderId() { return orderId; }
        public String getStatus() { return status; }
    }

    public static class InventoryStatus {
        private Map<String, Object> status;

        public InventoryStatus(Map<String, Object> status) {
            this.status = status;
        }

        public Map<String, Object> getStatus() { return status; }
    }
    
    public static class InventoryInitialized {
        private String status;
        
        public InventoryInitialized(String status) {
            this.status = status;
        }
        
        public String getStatus() { return status; }
    }
    
    // 库存状态类
    public static class InventoryState {
        private Map<String, Integer> availableInventory = new ConcurrentHashMap<>();
        private Map<String, Map<String, Integer>> reservedInventory = new ConcurrentHashMap<>();
        private LocalDateTime lastUpdated = LocalDateTime.now();
        
        // Getters and Setters
        public Map<String, Integer> getAvailableInventory() { return availableInventory; }
        public void setAvailableInventory(Map<String, Integer> availableInventory) { this.availableInventory = availableInventory; }
        
        public Map<String, Map<String, Integer>> getReservedInventory() { return reservedInventory; }
        public void setReservedInventory(Map<String, Map<String, Integer>> reservedInventory) { this.reservedInventory = reservedInventory; }
        
        public LocalDateTime getLastUpdated() { return lastUpdated; }
        public void setLastUpdated(LocalDateTime lastUpdated) { this.lastUpdated = lastUpdated; }
    }
}

